// SKNotes - a note taking and gathering tool
// Copyright (C) 2009  Stefan Kueng
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

namespace SKNotes.Configuration
{
    using System;
    using System.Configuration;

	public abstract class Setting : ISetting
	{
		public event SettingValueCancelEventHandler ValueSaving;
		public event SettingValueCancelEventHandler ValueLoading;

		protected Setting()
		{
			Scope = SettingScope.User;
		}

		public ApplicationSettings ApplicationSettings { get; set; }

		public SettingScope Scope { get; set; }

		public string Description { get; set; }

		public bool ThrowOnErrorDeserializing { get; set; }

		public bool ThrowOnErrorSerializing { get; set; }

		public bool ThrowOnErrorSaving { get; set; }

		public bool ThrowOnErrorLoading { get; set; }

		public abstract bool HasChanged { get; }

		public abstract void Load();

		public abstract void Save();

		protected virtual object OnValueSaving( string name, object value )
		{
			if ( ValueSaving == null )
			{
				return value;
			}

			SettingValueCancelEventArgs e = new SettingValueCancelEventArgs( this, name, value );
			ValueSaving( this, e );
			if ( e.Cancel )
			{
				return null;
			}

			return e.TargetValue;
		}

		protected virtual object OnValueLoading( string name, object value )
		{
			if ( ValueLoading == null )
			{
				return value;
			}

			SettingValueCancelEventArgs e = new SettingValueCancelEventArgs( this, name, value );
			ValueLoading( this, e );
			if ( e.Cancel )
			{
				return null;
			}

			return e.TargetValue;
		}

		protected void CreateSettingProperty( string name, Type type, SettingsSerializeAs serializeAs, object defaultValue )
		{
			ApplicationSettings applicationSettings = ApplicationSettings;
			if ( applicationSettings == null || applicationSettings.DefaultProvider == null )
			{
				return;
			}

			SettingsProperty settingsProperty = applicationSettings.Properties[ name ];
			if ( settingsProperty != null )
			{
				return; // already present
			}

			SettingsAttributeDictionary attributes = new SettingsAttributeDictionary();
			SettingAttribute attribute;
			switch ( Scope )
			{
				case SettingScope.Application:
					// attribute = new ApplicationScopedSettingAttribute();
					throw new NotImplementedException(); // currently not supported
				case SettingScope.User:
					attribute = new UserScopedSettingAttribute();
					break;
				default:
					return;
			}
			attributes.Add( attribute.TypeId, attribute );

			settingsProperty = new SettingsProperty(
				name, // name
				type, // type
				applicationSettings.DefaultProvider, // settings provider
				false, // is readonly
				defaultValue, // default
				serializeAs, // serialize as
				attributes, // attribute
				ThrowOnErrorDeserializing, // throw on deserialization
				ThrowOnErrorSerializing ); // throw on serialization

			applicationSettings.Properties.Add( settingsProperty );
		}

		protected void CreateSettingPropertyValue( string name, Type type, SettingsSerializeAs serializeAs, object defaultValue )
		{
			CreateSettingProperty( name, type, serializeAs, defaultValue );

			ApplicationSettings applicationSettings = ApplicationSettings;
			SettingsProperty settingsProperty = applicationSettings.Properties[ name ];
			if ( settingsProperty != null )
			{
				return; // already present
			}

			SettingsPropertyValue settingsPropertyValue = new SettingsPropertyValue( settingsProperty );
			applicationSettings.PropertyValues.Add( settingsPropertyValue );
		}

		protected object LoadValue( string name, Type type, SettingsSerializeAs serializeAs )
		{
			return LoadValue( name, type, serializeAs, null );
		} 

		protected object LoadValue( string name, Type type, SettingsSerializeAs serializeAs, object defaultValue )
		{
			CreateSettingProperty( name, type, serializeAs, defaultValue );
			object value = ApplicationSettings[ name ];
			return OnValueLoading( name, value );
		} 

		protected void SaveValue( string name, Type type, SettingsSerializeAs serializeAs, object value )
		{
			SaveValue( name, type, serializeAs, value, null );
		}

		protected void SaveValue( string name, Type type, SettingsSerializeAs serializeAs, object value, object defaultValue )
		{
			if ( OnValueSaving( name, value ) == null )
			{
				return;
			}

			CreateSettingPropertyValue( name, type, serializeAs, defaultValue );
			ApplicationSettings[ name ] = value;
		} 
	} 
}
